import { defaultsDeep as lodashDefaultsDeep, isEmpty as lodashIsEmpty, isNumber, unset, defaults, pickBy, cloneDeep, escapeRegExp, forIn, filter, isBoolean, isFunction, find, forEach, isString, sortBy, pick, get, isPlainObject } from "lodash";
import {
    construct,
    destruct
} from '@aximario/json-tree';

/**
 * todo 是否可以用findKey来查找对应的元素位置 然后取值
 * 如果需要调整值的话用set来调整
 *
 * @param {*} data 数据源
 * @param {Function} callback 查询条件{a:1,b:2}或者查询方法
 * @param {string} [childName='children'] 子节点字段名称
 */
export function findTree(data: any, queryData: any, childName: string = 'children') {
    // 根据条件查询数据
    let result = find(data, queryData);
    if (!result) {
        // 如果查询不到数据，遍历子节点
        forEach(data, item => {
            const list = item[childName];
            if (!isEmpty(list)) {
                // 如果子节点中查到数据，结束循环
                result = findTree(list, queryData, childName);
                if (result) {
                    return false;
                }
            }
        })
    }
    return result;
}

/**
 * 根据查询调整模糊查询树形数据
 *
 * @param {*} treeData 数据源
 * @param {*} queryData 查询条件{a:1,b:2}或者查询方法
 * @param {*} [{
 *         id = 'id',
 *         pid = 'parentId',
 *         children = 'children',
 *         orderBy 排序方式
 *     }={}]
 */
export function queryTree(treeData: any, queryData: any, {
    id = 'id',
    pid = 'parentId',
    children = 'children',
    orderBy
}: any = {}) {
    let queryFun: any;
    if (isFunction(queryData)) {
        queryFun = queryData;
    } else if (!isEmpty(queryData)) {
        // 清除查询条件中的空数据
        queryData = this.clearObject(cloneDeep(queryData));
        // 根据查询条件生成模糊查询正则表达式
        forIn(queryData, (value: any, key: any) => {
            queryData[key] = new RegExp(escapeRegExp(value), 'i')
        })
        queryFun = function (item: any) {
            let is = true;
            forIn(queryData, (value: any, key: any) => {
                if (!value.test(item[key])) {
                    is = false;
                }
            })
            return is;
        }
    }
    // 如果查询方法存在
    if (queryFun && !isEmpty(treeData)) {
        // 深拷贝
        treeData = cloneDeep(treeData);
        // 将树形数据转为扁平数据
        treeData = destruct(treeData, {
            id, pid, children
        })
        // 根据查询条件过滤数据
        treeData = filter(treeData, queryFun);
        // 如果有排序字段，重新排序
        if (!isEmpty(orderBy)) {
            treeData = sortBy(treeData, orderBy);
        }
        // 再将扁平数据转换为树形数据
        treeData = construct(treeData, {
            id, pid, children
        });
    }
    return treeData;
}

/**
 * 判断是否为空对象，空字符串，null
 * {},[],'',null会返回true
 * {a:''}这种也会返回true
 * @export
 * @param {*} v 数据
 * @return {*} 是否为空
 */
export function isEmpty(v: any): any {
    if (isNumber(v)) {
        // 只要是数字就不算空
        return false;
    } else if (isPlainObject(v)) {
        // 如果是obj类型，清除掉里面的空数据
        v = clearObject(v);
    }
    return lodashIsEmpty(v);
}

/**
 * 清除对象中空数据
 *
 * @export
 * @param {*} o 数据
 * @return {*} 新数据
 */
export function clearObject(o: any): any {
    return pickBy(o, (item: any) => {
        return !isEmpty(item);
    });
}

export function getListByConfig(list: any, config: any, isDeep = true): any {
    const data = [];
    list.forEach((item: any) => {
        item = getDataByConfig(item, config, isDeep);
        if (item) {
            data.push(item);
        }
    })
    return data;
}

/**
 * 根据映射配置获取数据
 * 有一个字段无值则返回null
 * @export
 * @param {*} data 原始数据
 * @param {*} config 映射配置
 * @return {*} 新数据
 */
export function getDataByConfig(data: any, config: any, isDeep = false): any {
    const item: any = {};
    let is = true;
    for (const name in config) {
        // 根据映射配置获取值
        const key = config[name],
            value = get(data, key);
        // 如果数据为空
        if (isEmpty(value)) {
            // 标识并跳出循环
            is = false;
            break;
        } else {
            item[name] = value;
            // 删除已经重新命名的数据
            unset(data, key);
        }
    }
    if (is && isDeep) {
        // 追加未处理数据
        defaults(item, data);
    }
    return is ? item : null;
}

/**
 * 深度合并配置与默认配置
 * 配置会覆盖默认配置
 * @export
 * @param {*} params 配置 如果配置是布尔类型/字符串类型，直接返回配置
 * @param {*} defaultParams 默认配置
 * @return {*} 合并后配置
 */
export function defaultsDeep(params: any, defaultParams: any): any {
    // 如果配置是布尔类型/字符串类型，直接返回配置
    if (isBoolean(params) || isString(params)) {
        return params;
    }
    return lodashDefaultsDeep(params, defaultParams);
}

/**
 * 正则表达式验证
 *
 * @export
 * @param {*} regex 正则表达式
 * @param {*} value 值
 * @return {*} 是否通过验证
 */
export function regexVerify(regex: any, value: any): any {
    return !isEmpty(value) ? regex.test(value) : true;
}

/**
 * 验证链接
 *
 * @export
 * @param {*} value 值
 * @return {*} 是否通过验证
 */
export function linkVerify(value: any): any {
    return regexVerify(/(http|https):\/\/([\w.]+\/?)\S*/, value)
}

/**
 * 过滤列表数据，只返回指定字段
 *
 * @param {*} list [{a:1,b:2,c:3}]
 * @param {*} keys ['a','b']
 * @returns [{a:1,b:2}]
 */
export function pickList(list: any, keys: any) {
    const data: any = [];
    forEach(list, item => {
        data.push(pick(item, keys))
    })
    return data;
}


export default {}